import React, {PureComponent} from "react";
import PropTypes from "prop-types";
import globalHelper from "../../utils/globalHelper";
import {forEach, forIn, isFunction, toLower} from "lodash-es";
import {GlobalConsumer} from "../GlobalProvider";
import {getRandomKey} from "jh-utils";

export default class BaseComp extends PureComponent {

    static propTypes = {
        /**
         * 具体应用的实例
         * @type {{
         * appInfo?: {id: number, code: string, name: string},
         * fetchList?: function,
         * fuzzyMath?: string,
         * fetchFinder?: function,
         * fetchCombo?: function,
         * handleClickBtn?: function,
         * handleClickMutexBtn?: function,
         * jump2Detail?: function,
         * setByKeyValue?: function,
         * setFieldInsByName?: function,
         * setBtnInsById?: function,
         * setLinkFieldIns?: function,
         * onFinderAction?: function
         * }}
         */
        appins: PropTypes.object,
        /**
         * @type {{
         *     page?: string
         * }}
         */
        customprops: PropTypes.object,
        onRef: PropTypes.func,
        /**
         * 需要在 cdm 执行的方法。用于 afc
         */
        exeInMount: PropTypes.func,
        componentType: PropTypes.string
    };

    helpers = {};

    COMP_ID = getRandomKey();

    constructor(props) {
        super(props);
        this.helpers = globalHelper.values;
        this.state = {
            // fieldCtrl: 'undefined' !== typeof props.fieldCtrl ? props.fieldCtrl : FieldCtrl.NORMAL,
            compMoreProps: {}, // 组件的额外属性。
            ...this.initState(props)
        };
        /**
         * 组件共有的属性值。用于辅助快速过滤子组件不需要的属性值
         * @type {string[]}
         */
        this.commonProps = [
            'compData', 'appins', 'customprops', 'onRef', 'exeInMount', 'dataType', 'componentType',
            'multi', 'floatNum', 'format',
            ...this.moreCommonProps()
        ]
    }

    initState(props) {
        return {}
    }

    moreCommonProps() {
        return []
    }

    componentDidMount() {
        this.compMounted = true;
        this.props.onRef && this.props.onRef(this);
        this.props.exeInMount && this.props.exeInMount(this);
    }

    componentWillUnmount() {
        this.unmounted = true;
    }

    setEnabled(enabled, afterCb) {
        this.setCompProps({disabled: !enabled}, afterCb);
    }

    /**
     * 设置字段的权限状态。对应 FieldCtrl
     * @param fieldCtrl
     */
    setFieldCtrl(fieldCtrl) {
        // this.setState({fieldCtrl});
        this.setCompProps({fieldCtrl});
    }

    getFieldCtrl() {
        return this.getPropsByName('fieldCtrl');
    }

    /**
     * 组件的额外属性。与 state.compMoreProps 保持一致。
     * 之所以有这个变量，是为了支持“同步执行情况下，在 setCompProps() 之后，修改立即起效”
     * @type {{[x]: any}}
     */
    compMoreProps = {};

    /**
     * 设置此字段对应的组件的属性，例如 InputComp、NumberInput 等组件。
     * 一般用于 afc 调用，实现个性化逻辑。
     * @param compMoreProps {object} 属性值，例如设置 {onChange: (value) => {// 你的逻辑}}。更多属性参考字段的具体组件。
     * @param afterCb
     */
    setCompProps(compMoreProps = {}, afterCb) {
        this.compMoreProps = {...this.compMoreProps, ...compMoreProps};
        this.setState({compMoreProps: {...this.state.compMoreProps, ...compMoreProps}}, afterCb);
    }

    reRender(afterCb) {
        this.setState({randomKey: getRandomKey()}, afterCb);
    }

    getAppCode() {
        const {appCode, appins} = this.props;
        return appCode ? appCode : (
            appins && appins.appInfo ? appins.appInfo.code : ''
        );
    }

    /**
     * 获取属性对象
     */
    getProps() {
        const reProps = {...this.props};
        const compMoreProps = this.compMoreProps;
        // const {compMoreProps} = this.state;
        forIn(compMoreProps, (val, key) => {
            if ('undefined' !== typeof val && null !== val) {
                reProps[key] = val;
            }
        });
        return reProps;
    }

    /**
     * 根据属性名获取属性值
     * @param propName {string} 属性名
     */
    getPropsByName(propName) {
        let reVal = this.props[propName];
        const compMoreProps = this.compMoreProps;
        // const {compMoreProps} = this.state;
        if (compMoreProps && 'undefined' !== typeof compMoreProps[propName] && null !== compMoreProps[propName]) {
            reVal = compMoreProps[propName];
        }
        return reVal;
    }

    getPropsByNames(names) {
        let reObj = {};
        forEach(names, (name) => {
            reObj[name] = this.getPropsByName(name);
        });
        return reObj;
    }

    /**
     * 从 props 和 appins 中获取 name 对应的属性。
     * 优先级：props > appins
     * @param name {string} 属性值
     */
    getFromPropAppins(name) {
        let val = this.getPropsByName(name);
        if ('undefined' === typeof val || null === val) {
            const {appins} = this.props;
            val = appins && appins[name] ? (
                isFunction(appins[name]) ? appins[name].bind(appins) : appins[name]
            ) : null
        }
        return val;
    }

    /**
     * 执行 props 的方法
     * @param funcName {string} 方法名
     * @return {function(): *}
     */
    runPropsFunc(funcName) {
        const $this = this;

        return function () {
            let reVal;

            if (isFunction($this.props[funcName])) {
                reVal = $this.props[funcName](...arguments);
            }

            const compMoreProps = $this.compMoreProps;
            // const {compMoreProps} = $this.state;
            if (compMoreProps && isFunction(compMoreProps[funcName])) {
                reVal = compMoreProps[funcName](...arguments);
            }
            return reVal;
        }
    }

    /**
     * 执行“应用实例（appins）”的方法
     * @param funcName {string} 方法名称
     * @return {function(...[*]=)}
     */
    runAppinsFunc(funcName) {
        const {appins} = this.props;

        return function () {

            if (appins && isFunction(appins[funcName])) {
                appins[funcName](...arguments);
            }
        }
    }

    hasPropFunc(funcName) {
        const compMoreProps = this.compMoreProps;
        // const {compMoreProps} = this.state;
        let had = false;

        if (isFunction(this.props[funcName])
            || compMoreProps && isFunction(compMoreProps[funcName])) {
            had = true;
        }
        return had;
    }

    openWin() {
        if (isFunction(window.openWin)) {
            window.openWin(...arguments);
        } else {
            window.open(...arguments);
        }
    }

    /**
     * 根据 GlobalApi 的配置发请求
     * @param apiConf {{api: string, type: string}} 接口配置。对应 GlobalApi 的配置
     * @param params
     * @param options
     */
    request(apiConf, params = {}, options = {}) {
        const tmpFunc = (rsp) => {
            if (isFunction(apiConf.func)) {
                const funcRsp = apiConf.func(rsp);
                if (funcRsp) return funcRsp;
            }
            return rsp;
        };

        if ('get' === toLower(apiConf.type)) {
            return this.reqGet(apiConf.api, params, options).then(tmpFunc);

        } else if ('post' === toLower(apiConf.type)) {
            return this.jsonPost(apiConf.api, params, options).then(tmpFunc);
        }
    }

    reqGet(api, params = {}, options = {}) {
        return this._requestFunc('reqGet', api, params, options);
    }

    jsonPost(api, params = {}, options = {}) {
        return this._requestFunc('jsonPost', api, params, options);
    }

    formPost(api, params = {}, options = {}) {
        return this._requestFunc('formPost', api, params, options);
    }

    requestFunc(api, options = {}) {
        const request = this.helpers.request || {};
        const func = request.request;

        if (isFunction(func)) {
            return func(api, options);
        } else {
            return new Promise((resolve => {
                resolve(null);
            }));
        }
    }

    newAbortCtrl() {
        return this._requestFunc('newAbortCtrl');
    }

    abortFetch(abortCtrl) {
        return this._requestFunc('abortFetch', abortCtrl);
    }

    _requestFunc(funcName, api, params, options) {
        const request = this.helpers.request || {};
        const func = request[funcName];

        if (isFunction(func)) {
            return func(api, params, options);
        } else {
            return new Promise((resolve => {
                resolve(null);
            }));
        }
    }

    getLocale() {
        const {localeUtils} = this.helpers;
        const {getLocale} = (localeUtils ? localeUtils : {});
        return getLocale ? getLocale() : '';
    }

    formatMsgByCn(cn, values = {}) {
        const {localeUtils} = this.helpers;
        const {formatMsgByCn} = (localeUtils ? localeUtils : {});
        return formatMsgByCn ? formatMsgByCn(cn, values) : cn;
    }

    myFormatMessage(desc, values = {}) {
        const {localeUtils} = this.helpers;
        const {myFormatMessage} = (localeUtils ? localeUtils : {});
        return myFormatMessage ? myFormatMessage(desc, values) : desc;
    }

    mainRender(context) {
        return null;
    }

    render() {
        return <GlobalConsumer>
            {this.mainRender.bind(this)}
        </GlobalConsumer>;
    }
}